"""统一申请详情资源。

提供 /api/applications/<application_id>，返回业务申请 + 流程步骤进度。
"""
import json
from typing import Any, Dict, Optional

from flask_restful import Resource
from ..models import LeaveApplication, PurchaseApplication, ProcessTaskDefinition
from ..utils.helpers import success_response, error_response, handle_errors
from ..utils.flowable_client import FlowableClient
try:
    from server.config.config import Config  # type: ignore
except ModuleNotFoundError:
    from config.config import Config  # type: ignore


def _leave_detail(app: LeaveApplication):
    d = app.to_dict()
    d['business_kind'] = 'leave'
    return d


def _purchase_detail(app: PurchaseApplication):
    d = app.to_dict()
    d['business_kind'] = 'purchase'
    return d


def _resolve_operator_from_assignee(expr: Optional[str],
                                    process_vars: Dict[str, Any],
                                    detail: Dict[str, Any],
                                    missing_fallback: str) -> str:
    """根据 flowable:assignee 表达式推断执行人。"""
    if not expr:
        return missing_fallback
    stripped = expr.strip()
    if stripped.startswith('${') and stripped.endswith('}'):
        inner = stripped[2:-1].strip()
        if not inner:
            return missing_fallback
        value = process_vars.get(inner)
        if value is None:
            value = detail.get(inner)
        return str(value) if value not in (None, '') else missing_fallback
    # 直接配置具体用户名/ID
    return stripped


class ApplicationDetailResource(Resource):
    """根据申请 ID 返回详情 + 流程步骤。"""

    def __init__(self):
        self.flowable_client = FlowableClient(
            Config.FLOWABLE_REST_URL,
            Config.FLOWABLE_REST_USER,
            Config.FLOWABLE_REST_PASSWORD
        )

    @handle_errors
    def get(self, application_id: int):
        leave_app = LeaveApplication.query.get(application_id)
        purchase_app = None if leave_app else PurchaseApplication.query.get(application_id)
        detail = _leave_detail(leave_app) if leave_app else (_purchase_detail(purchase_app) if purchase_app else None)
        if not detail:
            return error_response('申请不存在', 404)

        pid = detail.get('process_instance_id')
        steps: list[dict] = []
        current_step_index = 0
        process_definition_id = None
        # 预先保存的流程节点定义（部署阶段解析入库）
        definition_tasks: list[ProcessTaskDefinition] = []
        definition_task_map: Dict[str, ProcessTaskDefinition] = {}
        definition_conditions: Dict[str, list] = {}
        process_variables: Dict[str, Any] = {}

        if pid:
            try:
                process_instance = {}
                try:
                    process_instance = self.flowable_client.get_process_instance(pid)
                except Exception:
                    process_instance = {}
                try:
                    process_variables = self.flowable_client.get_process_instance_variables(pid)
                except Exception:
                    process_variables = {}
                process_definition_id = process_instance.get('processDefinitionId')
                if process_definition_id:
                    try:
                        definition_tasks = ProcessTaskDefinition.query.filter_by(process_definition_id=process_definition_id)\
                            .order_by(ProcessTaskDefinition.sequence_index).all()
                        for dt in definition_tasks:
                            definition_task_map[dt.activity_id] = dt
                            try:
                                definition_conditions[dt.activity_id] = json.loads(dt.conditions_json) if dt.conditions_json else []
                            except Exception:
                                definition_conditions[dt.activity_id] = []
                    except Exception:
                        definition_tasks = []
                        definition_task_map = {}
                        definition_conditions = {}
                activities = self.flowable_client.get_historic_activity_instances(pid)
                # 若流程实例缺少 processDefinitionId，则无法加载预定义节点，仅显示已有历史与当前任务。
                runtime_tasks = []
                try:
                    runtime_tasks = self.flowable_client.get_tasks(process_instance_id=pid)
                    print(f"运行时任务: {(runtime_tasks)}")
                except Exception:
                    runtime_tasks = []
                filtered = [a for a in activities if a.get('activityType') in ('startEvent', 'userTask', 'endEvent')]
                type_order = {'startEvent': 0, 'userTask': 1, 'endEvent': 2}
                sorted_filtered = sorted(filtered, key=lambda a: (type_order.get(a.get('activityType', ''), 99), a.get('startTime') or ''))
                current_step_index = -1
                for act in sorted_filtered:
                    act_id = act.get('activityId') or act.get('id')
                    name = act.get('activityName') or act_id or act.get('id')
                    completed = act.get('endTime') is not None
                    status = '已完成' if completed else '进行中'
                    if act.get('activityType') == 'userTask' and not completed and current_step_index < 0:
                        current_step_index = len(steps)
                    activity_type = act.get('activityType')
                    if activity_type == 'startEvent':
                        operator = detail.get('applicant_id') or '发起人'
                    elif activity_type == 'userTask':
                        definition_task = definition_task_map.get(act_id)
                        operator = act.get('assignee') or _resolve_operator_from_assignee(
                            definition_task.assignee if definition_task else None,
                            process_variables,
                            detail,
                            '未指定'
                        )
                    elif activity_type == 'endEvent':
                        operator = '系统'
                    elif activity_type == 'exclusiveGateway':
                        # 已过滤，不会进入
                        operator = '系统'
                    else:
                        operator = '系统'
                    # 条件：来自预定义表
                    conditions = []
                    def_task = definition_task_map.get(act_id)
                    if def_task:
                        conditions = definition_conditions.get(def_task.activity_id, [])
                    steps.append({
                        'id': act_id,
                        'name': name,
                        'activity_type': activity_type,
                        'status': status,
                        'operator': operator,
                        'start_time': act.get('startTime'),
                        'end_time': act.get('endTime'),
                        'conditions': conditions
                    })
                historic_user_ids = {s['id'] for s in steps if s.get('activity_type') == 'userTask'}
                for rt in runtime_tasks:
                    rtid = rt.get('id')
                    rt_name = rt.get('name') or rtid
                    if rtid in historic_user_ids or rt_name in {s['name'] for s in steps}:
                        continue
                    steps.append({
                        'id': rtid,
                        'name': rt_name,
                        'activity_type': 'userTask',
                        'status': '进行中',
                        'operator': rt.get('assignee') or '未指定',
                        'start_time': rt.get('createTime'),
                        'end_time': None
                    })
                    if current_step_index < 0:
                        current_step_index = len(steps) - 1
                if current_step_index < 0 and steps:
                    if all(s.get('status') == '已完成' for s in steps if s.get('activity_type') == 'userTask'):
                        current_step_index = len(steps) - 1
                    else:
                        current_step_index = 0
            except Exception as e:
                steps = [{'id': 'error', 'name': '流程步骤获取失败', 'activity_type': 'system', 'status': str(e), 'operator': '系统'}]
                current_step_index = 0

        # 追加未来步骤：定义中存在但尚未出现的 userTask
        future_steps = []
        if definition_tasks:
            existing_ids = {s['id'] for s in steps}
            for def_task in definition_tasks:
                if def_task.activity_type != 'userTask':
                    continue
                if def_task.activity_id in existing_ids:
                    continue
                raw_conditions = definition_conditions.get(def_task.activity_id, [])
                future_steps.append({
                    'id': def_task.activity_id,
                    'name': def_task.activity_name or def_task.activity_id,
                    'activity_type': 'userTask',
                    'status': '未开始',
                    'operator': _resolve_operator_from_assignee(def_task.assignee, process_variables, detail, '待生成'),
                    'start_time': None,
                    'end_time': None,
                    'conditions': raw_conditions
                })
        # 合并顺序：startEvent -> 已/进行中 userTask 按出现顺序 -> future 未开始 -> endEvent
        start_events = [s for s in steps if s['activity_type'] == 'startEvent']
        user_tasks_done = [s for s in steps if s['activity_type'] == 'userTask']
        end_events = [s for s in steps if s['activity_type'] == 'endEvent']
        future_user_tasks = [s for s in future_steps if s['activity_type'] == 'userTask']
        merged_steps = start_events + user_tasks_done + future_user_tasks + end_events

        if merged_steps:
            new_current = None
            for idx, s in enumerate(merged_steps):
                if s['status'] == '进行中':
                    new_current = idx
                    break
            if new_current is None:
                for idx, s in enumerate(merged_steps):
                    if s['status'] == '未开始':
                        new_current = idx
                        break
            if new_current is None:
                new_current = len(merged_steps) - 1
            current_step_index = new_current

        payload = {
            'id': detail['id'],
            'business_kind': detail['business_kind'],
            'status': detail.get('status'),
            'process_instance_id': pid,
            'process_definition_id': process_definition_id,
            'detail': detail,
            'steps': merged_steps,
            'current_step': current_step_index
        }
        return success_response(payload, '获取申请详情成功')
